package userserv

import (
	"codedef"
	"config"
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/http"
	"rhelper"
	"time"
)

var (
	luaScript = `local value = redis.call('HGET', KEYS[1], 'key')
	             if tonumber(KEYS[2]) == tonumber(value) then
		     local cid = redis.call('HGET', KEYS[1], 'cid')
	             return cid
	             else
	             redis.call('HMSET', KEYS[1], 'key', KEYS[2], 'serverId', KEYS[3])
	             return false
	             end`
)

// counter available account
//func setAccountInNormal(account string) {
//	t := time.Now().UTC()
//	tStr := t.Format("20060102150405")
//
//	rconn := rhelper.Pool().Get()
//	defer rconn.Close()
//
//	id, err := redis.String(rconn.Do("HGET", rhelper.AccountHash+account, "id"))
//	if err != nil {
//		log.Println("setAccountInNormal err:", err)
//		return
//	}
//
//	rconn.Send("MULTI")
//	rconn.Send("ZADD", rhelper.AccountSortInNormal, tStr, id)
//	rconn.Send("ZREM", rhelper.AccountSortInProblem, id)
//	_, err = rconn.Do("EXEC")
//	if err != nil {
//		log.Println("setAccountInNormal failed, error:", err)
//	}
//
//}

// if device has connect to server, retrun true
func checkWaitKey(account string, key int, userServer string) string {
	rconn := rhelper.Pool().Get()
	defer rconn.Close()

	var getScript = redis.NewScript(3, luaScript)
	log.Println(rhelper.WaitKey+account, key, userServer)
	reply, err := redis.String(getScript.Do(rconn, rhelper.WaitKey+account, key, userServer))
	if err != nil && err != redis.ErrNil {
		log.Println("checkWaitKey err: ", err)
	}

	//if reply == 1 {
	//	return true
	//}

	return reply
}

func onWaitDevRegister(w http.ResponseWriter, r *http.Request) {
	type WaitKeyParams struct {
		Key     int    `json:"key"`
		Account string `json:"account"`
	}
	var uniqueId string
	uniqueId = r.Header.Get("id")

	log.Println("onWaitDevRegister, uniqueId:", uniqueId)
	if r.ContentLength < 1 {
		log.Println("onWaitDevRegister failed, content length is zero")
		replyError(w, codedef.ERR_REQUEST_INVALID_PARAM)
		return
	}

	message := make([]byte, r.ContentLength)
	n, _ := r.Body.Read(message)
	if n != int(r.ContentLength) {
		log.Println("onWaitDevRegister failed, can't read request body")
		replyError(w, codedef.ERR_REQUEST_INVALID_PARAM)
		return
	}

	var waitKeyParams WaitKeyParams
	err := json.Unmarshal(message, &waitKeyParams)
	if err != nil {
		log.Println("onWaitDevRegister failed, json decode failed:", err)
		replyError(w, codedef.ERR_DECODE)
		return
	}
	log.Println(waitKeyParams)

	cid := checkWaitKey(waitKeyParams.Account, waitKeyParams.Key, config.ServerId)
	if cid != "" {
		log.Println("controller has connect to server")

		replyBuffer(w, []byte(fmt.Sprintf("{\"cid\":\"%s\"}", cid)))
		go GetRuntimeInfo(w, getOnlineControllerById(cid))
		return
	}

	log.Println("wait for device connect to server")

	wait := make(chan int, 1)
	waitCid := make(chan string, 1)
	setWaitKey(waitKeyParams.Account, wait, waitCid)

	select {
	case key := <-wait:
		if key == waitKeyParams.Key {
			//setAccountInNormal(waitKeyParams.Account)
			wcid := <-waitCid
			replyBuffer(w, []byte(fmt.Sprintf("{\"cid\":\"%s\"}", wcid)))
			log.Println("/waitRegister reply, account: ", waitKeyParams.Account)
			//go GetRuntimeInfo(w, getOnlineControllerById(wcid))
		} else {
			log.Printf("wait key not match, device key: %d, httpwait key: %d", key, waitKeyParams.Key)
		}
		break
	case <-time.After(time.Second * 60):
		//delete(devserv.WaitKey, waitKeyParams.Account)
		deleteWaitKey(waitKeyParams.Account)
		replyError(w, codedef.ERR_TIME_OUT)
		log.Println("wait device register timeout， account: ", waitKeyParams.Account)
		break
	}
}

func init() {
	myMux.muxHandlers.HandleFunc("/waitDevRegister", onWaitDevRegister)
	myMux.ignoreToken["/waitDevRegister"] = true
}
